package net.tplusplus.test.drools.speedtest;

import java.util.Collections;
import java.util.List;

import net.tplusplus.drools.speedtest.bank.Account;
import net.tplusplus.drools.speedtest.facts.AccountingPeriod;
import net.tplusplus.drools.speedtest.facts.Cashflow;
import net.tplusplus.drools.speedtest.facts.UpdatingAccount;
import net.tplusplus.rules.runner.StatefulRunner;
import net.tplusplus.rules.runner.StatelessRunner;
import net.tplusplus.rules.runner.rao.Fact;
import net.tplusplus.test.drools.speedtest.data.TestData;
import net.tplusplus.utils.TimedResults;

import org.drools.RuleBase;

public class SpeedTest1
{
	public static void main(String[] args) throws Exception
	{
		long[] intervals = { TestData.YEAR_ms, TestData.WEEK_ms, TestData.DAY_ms, TestData.HOUR_ms,
				/* TestData.HOUR_ms / 10, TestData.HOUR_ms / 20 */ };
		int[] iterationsList = { 2,  10, 50, 100 };

		for (long interval : intervals)
		{
			TestData.resetCashflows(interval);

			for (int iterations : iterationsList)
			{
				runTest1(iterations);
				runTest2(iterations);
				runTest3(iterations);
				runTest4(iterations);
				runTest5(iterations);
				runTest6(iterations);
				runTest7(iterations);
				runTest8(iterations);
				runTest9(iterations);
			}
		}
	}

	public static void runTest1(int iterations) throws Exception
	{
		System.out.println("\nRunning Speed Test 1 - NO CACHING");
		TimedResults results = new TimedResults();

		StatefulRunner runner = new StatefulRunner();
		runner.addRules("/net/tplusplus/drools/speedtest/rules/test1/test01.drl");

		List<Fact> allFacts = TestData.getAllFacts();
		runner.addFacts(allFacts);

		System.out.println("Iterations: " + iterations);
		System.out.println("Number of facts: " + runner.getFacts().size());

		for (int i = 0; i < iterations; i++)
		{
			TestData.resetAccounts();

			long starttime = System.currentTimeMillis();

			runner.createRuleBase();
			runner.createWorkingMemory();
			runner.runRules();

			long endtime = System.currentTimeMillis();
			long timetaken = endtime - starttime;

			results.addTime(timetaken);
		}

		System.out.println("fastest time: " + results.getFastest() + " (ms)");
		System.out.println("slowest time: " + results.getSlowest() + " (ms)");
		System.out.println("average time: " + results.getAverage() + " (ms)");
	}

	public static void runTest2(int iterations) throws Exception
	{
		System.out.println("\nRunning Speed Test 2 - CACHING RULEBASE");
		TimedResults results = new TimedResults();

		StatefulRunner runner = new StatefulRunner();
		runner.addRules("/net/tplusplus/drools/speedtest/rules/test1/test01.drl");

		List<Fact> allFacts = TestData.getAllFacts();
		runner.addFacts(allFacts);

		System.out.println("Iterations: " + iterations);
		System.out.println("Number of facts: " + runner.getFacts().size());

		RuleBase cachedRuleBase = null;

		for (int i = 0; i < iterations; i++)
		{
			TestData.resetAccounts();

			long starttime = System.currentTimeMillis();

			if(cachedRuleBase == null)
			{
				runner.createWorkingMemory();
			}
			else
			{
				runner.setRuleBase(cachedRuleBase);
				runner.createWorkingMemory();
			}

			runner.runRules();
			runner.dispose();

			long endtime = System.currentTimeMillis();
			long timetaken = endtime - starttime;

			results.addTime(timetaken);
		}

		System.out.println("fastest time: " + results.getFastest() + " (ms)");
		System.out.println("slowest time: " + results.getSlowest() + " (ms)");
		System.out.println("average time: " + results.getAverage() + " (ms)");
	}

	public static void runTest3(int iterations) throws Exception
	{
		System.out.println("\nRunning Speed Test 3 - OPTIMISED DRL - changed order of facts");
		TimedResults results = new TimedResults();

		StatefulRunner runner = new StatefulRunner();
		runner.addRules("/net/tplusplus/drools/speedtest/rules/test1/test02.drl");

		List<Fact> allFacts = TestData.getAllFacts();
		runner.addFacts(allFacts);

		RuleBase cachedRuleBase = null;

		for (int i = 0; i < iterations; i++)
		{
			TestData.resetAccounts();

			long starttime = System.currentTimeMillis();

			if(cachedRuleBase == null)
			{
				runner.createWorkingMemory();
			}
			else
			{
				runner.setRuleBase(cachedRuleBase);
				runner.createWorkingMemory();
			}

			runner.runRules();
			runner.dispose();
			long endtime = System.currentTimeMillis();
			long timetaken = endtime - starttime;

			results.addTime(timetaken);
		}

		System.out.println("Iterations: " + iterations);
		System.out.println("Number of facts: " + runner.getFacts().size());
		System.out.println("fastest time: " + results.getFastest() + " (ms)");
		System.out.println("slowest time: " + results.getSlowest() + " (ms)");
		System.out.println("average time: " + results.getAverage() + " (ms)");
	}

	public static void runTest4(int iterations) throws Exception
	{
		System.out.println("\nRunning Speed Test 4 - OPTIMISED DRL - using long instead of Date");
		TimedResults results = new TimedResults();

		StatefulRunner runner = new StatefulRunner();
		runner.addRules("/net/tplusplus/drools/speedtest/rules/test1/test03.drl");

		List<Fact> allFacts = TestData.getAllFacts();
		runner.addFacts(allFacts);

		RuleBase cachedRuleBase = null;

		for (int i = 0; i < iterations; i++)
		{
			TestData.resetAccounts();

			long starttime = System.currentTimeMillis();

			if(cachedRuleBase == null)
			{
				runner.createWorkingMemory();
			}
			else
			{
				runner.setRuleBase(cachedRuleBase);
				runner.createWorkingMemory();
			}

			runner.runRules();
			runner.dispose();
			long endtime = System.currentTimeMillis();
			long timetaken = endtime - starttime;

			results.addTime(timetaken);
		}

		System.out.println("Iterations: " + iterations);
		System.out.println("Number of facts: " + runner.getFacts().size());
		System.out.println("fastest time: " + results.getFastest() + " (ms)");
		System.out.println("slowest time: " + results.getSlowest() + " (ms)");
		System.out.println("average time: " + results.getAverage() + " (ms)");
	}

	public static void runTest5(int iterations) throws Exception
	{
		System.out.println("\nRunning Speed Test 5 - OPTIMISED DRL - using Long instead of Date");
		TimedResults results = new TimedResults();

		StatefulRunner runner = new StatefulRunner();
		runner.addRules("/net/tplusplus/drools/speedtest/rules/test1/test04.drl");

		List<Fact> allFacts = TestData.getAllFacts();
		runner.addFacts(allFacts);

		RuleBase cachedRuleBase = null;

		for (int i = 0; i < iterations; i++)
		{
			TestData.resetAccounts();

			long starttime = System.currentTimeMillis();

			if(cachedRuleBase == null)
			{
				runner.createWorkingMemory();
			}
			else
			{
				runner.setRuleBase(cachedRuleBase);
				runner.createWorkingMemory();
			}

			runner.runRules();
			runner.dispose();
			long endtime = System.currentTimeMillis();
			long timetaken = endtime - starttime;

			results.addTime(timetaken);
		}

		System.out.println("Iterations: " + iterations);
		System.out.println("Number of facts: " + runner.getFacts().size());
		System.out.println("fastest time: " + results.getFastest() + " (ms)");
		System.out.println("slowest time: " + results.getSlowest() + " (ms)");
		System.out.println("average time: " + results.getAverage() + " (ms)");
	}

	public static void runTest9(int iterations) throws Exception
	{
		System.out.println("\nRunning Speed Test 9 - JAVA");
		TimedResults results = new TimedResults();

		RuleBase cachedRuleBase = null;

		for (int i = 0; i < iterations; i++)
		{
			List<Cashflow> cashflows = TestData.getAllCashflows();
			List<AccountingPeriod> accountingPeriods = TestData.getAccountingPeriods();
			List<UpdatingAccount> updatingAccounts = TestData.getAllUpdatingAccounts();

			TestData.resetAccounts();

			long starttime = System.currentTimeMillis();

			for (AccountingPeriod accountingPeriod : accountingPeriods)
			{
				for (Cashflow cashflow : cashflows)
				{
					if(cashflow.getDate().before(accountingPeriod.getStart()))
					{
						continue;
					}
					
					if(cashflow.getDate().after(accountingPeriod.getEnd()))
					{
						continue;
					}
					
					//System.out.println("Processing cashflow: "+cashflow);
					
					Account account = cashflow.getAccount();

					switch (cashflow.getType())
					{
						case Cashflow.CREDIT:
							//System.out.println("Credit: "+cashflow.getAmount());
							account.setBalance(account.getBalance() + cashflow.getAmount());
							break;
							
						case Cashflow.DEBIT:
							//System.out.println("Debit: "+cashflow.getAmount());
							account.setBalance(account.getBalance() - cashflow.getAmount());
							break;
					}
				}
				
				//System.out.print("Period End: "+accountingPeriod.getEnd());
				
				for(UpdatingAccount updatingAccount : updatingAccounts)
				{
					//System.out.println(" - Account "+updatingAccount.getAccountNo()+" - balance: "+updatingAccount.getAccount().getBalance());
				}
			}

			long endtime = System.currentTimeMillis();
			long timetaken = endtime - starttime;

			results.addTime(timetaken);
		}

		System.out.println("Iterations: " + iterations);
		System.out.println("Number of facts: " + TestData.getAllFacts().size());
		System.out.println("fastest time: " + results.getFastest() + " (ms)");
		System.out.println("slowest time: " + results.getSlowest() + " (ms)");
		System.out.println("average time: " + results.getAverage() + " (ms)");
	}
	
	public static void runTest6(int iterations) throws Exception
	{
		System.out.println("\nRunning Speed Test 6 - Collated Cashflows");
		TimedResults results = new TimedResults();

		StatefulRunner runner = new StatefulRunner();
		runner.addRules("/net/tplusplus/drools/speedtest/rules/test1/test05.drl");

		List<Cashflow> cashflows = TestData.getAllCashflows();
		List<AccountingPeriod> accountingPeriods = TestData.getAccountingPeriods();
		List<UpdatingAccount> updatingAccounts = TestData.getAllUpdatingAccounts();
		
		//runner.addFacts(updatingAccounts);
		
		RuleBase cachedRuleBase = null;

		for (int i = 0; i < iterations; i++)
		{
			TestData.resetAccounts();

			long starttime = System.currentTimeMillis();

			for (AccountingPeriod accountingPeriod : accountingPeriods)
			{
				runner.clearFacts();
				
				for (Cashflow cashflow : cashflows)
				{
					if(cashflow.getDate().before(accountingPeriod.getStart()))
					{
						continue;
					}
					
					if(cashflow.getDate().after(accountingPeriod.getEnd()))
					{
						continue;
					}

					runner.addFacts(cashflow);
				}
				
				if(cachedRuleBase == null)
				{
					runner.createWorkingMemory();
				}
				else
				{
					runner.setRuleBase(cachedRuleBase);
					runner.createWorkingMemory();
				}

				runner.runRules();
				runner.dispose();
				
				//System.out.print("Period End: "+accountingPeriod.getEnd());
			}

			long endtime = System.currentTimeMillis();
			long timetaken = endtime - starttime;

			results.addTime(timetaken);
		}

		System.out.println("Iterations: " + iterations);
		System.out.println("Number of facts: " + TestData.getAllFacts().size());
		System.out.println("fastest time: " + results.getFastest() + " (ms)");
		System.out.println("slowest time: " + results.getSlowest() + " (ms)");
		System.out.println("average time: " + results.getAverage() + " (ms)");
	}
	
	public static void runTest7(int iterations) throws Exception
	{
		System.out.println("\nRunning Speed Test 7 - Collated Cashflows with Stateless Engine");
		TimedResults results = new TimedResults();

		StatelessRunner runner = new StatelessRunner();
		runner.addRules("/net/tplusplus/drools/speedtest/rules/test1/test05.drl");

		List<Cashflow> cashflows = TestData.getAllCashflows();
		List<AccountingPeriod> accountingPeriods = TestData.getAccountingPeriods();
		List<UpdatingAccount> updatingAccounts = TestData.getAllUpdatingAccounts();
		
		//runner.addFacts(updatingAccounts);
		
		RuleBase cachedRuleBase = null;

		for (int i = 0; i < iterations; i++)
		{
			TestData.resetAccounts();

			long starttime = System.currentTimeMillis();

			for (AccountingPeriod accountingPeriod : accountingPeriods)
			{
				runner.clearFacts();
				
				for (Cashflow cashflow : cashflows)
				{
					if(cashflow.getDate().before(accountingPeriod.getStart()))
					{
						continue;
					}
					
					if(cashflow.getDate().after(accountingPeriod.getEnd()))
					{
						continue;
					}

					runner.addFacts(cashflow);
				}

				runner.runRules();
				
				//System.out.print("Period End: "+accountingPeriod.getEnd());
			}

			long endtime = System.currentTimeMillis();
			long timetaken = endtime - starttime;

			results.addTime(timetaken);
		}

		System.out.println("Iterations: " + iterations);
		System.out.println("Number of facts: " + TestData.getAllFacts().size());
		System.out.println("fastest time: " + results.getFastest() + " (ms)");
		System.out.println("slowest time: " + results.getSlowest() + " (ms)");
		System.out.println("average time: " + results.getAverage() + " (ms)");
	}
	
	public static void runTest8(int iterations) throws Exception
	{
		System.out.println("\nRunning Speed Test 8 - Collated Cashflows with Stateless Engine and Accumulate");
		TimedResults results = new TimedResults();

		StatelessRunner runner = new StatelessRunner();
		runner.addRules("/net/tplusplus/drools/speedtest/rules/test1/test06.drl");

		List<Cashflow> cashflows = TestData.getAllCashflows();
		List<AccountingPeriod> accountingPeriods = TestData.getAccountingPeriods();
		List<UpdatingAccount> updatingAccounts = TestData.getAllUpdatingAccounts();
		
		//runner.addFacts(updatingAccounts);
		
		RuleBase cachedRuleBase = null;

		for (int i = 0; i < iterations; i++)
		{
			TestData.resetAccounts();

			long starttime = System.currentTimeMillis();

			for (AccountingPeriod accountingPeriod : accountingPeriods)
			{
				runner.clearFacts();
				
				for (Cashflow cashflow : cashflows)
				{
					if(cashflow.getDate().before(accountingPeriod.getStart()))
					{
						continue;
					}
					
					if(cashflow.getDate().after(accountingPeriod.getEnd()))
					{
						continue;
					}

					runner.addFacts(cashflow);
				}

				runner.runRules();
				
				//System.out.print("Period End: "+accountingPeriod.getEnd());
			}

			long endtime = System.currentTimeMillis();
			long timetaken = endtime - starttime;

			results.addTime(timetaken);
		}

		System.out.println("Iterations: " + iterations);
		System.out.println("Number of facts: " + TestData.getAllFacts().size());
		System.out.println("fastest time: " + results.getFastest() + " (ms)");
		System.out.println("slowest time: " + results.getSlowest() + " (ms)");
		System.out.println("average time: " + results.getAverage() + " (ms)");
	}
}
